﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YJKRevitColumn.ColumnModule;
using YJKRevitColumn.Forms;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchUtils.ColumnProfileAnalyze;
using YJKRevitKernel.RevitTopologySuite;
using YJKLoopSearch;

namespace YJKRevitColumn.DataDefine
{
	internal class ColumnInsertManage
	{
		public ColumnInsertManage(ExternalCommandData cmdData)
		{
			this.m_cmdData = cmdData;
			this.m_uiApplication = cmdData.Application;
			this.m_uiDoc = this.m_uiApplication.ActiveUIDocument;
			this.m_doc = this.m_uiDoc.Document;
		}

		public bool ColumnMainOperator(ColumnInsertDlg dlg)
		{
			this.m_dlg = dlg;
			switch (dlg.GetCreateColType())
			{
			case CreateColumnType.eSelectPoint:
			case CreateColumnType.eSelectAxis:
			case CreateColumnType.eSelectGrids:
				return this.InsertColumnsOperator(dlg);
			case CreateColumnType.ePainter:
				return this.PrintOperator(dlg);
			case CreateColumnType.ePickupColumn:
				return this.PickColumnOperator(dlg);
			default:
				return true;
			}
		}

		private bool PrintOperator(ColumnInsertDlg dlg)
		{
			List<Element> list = new List<Element>();
			if (!this.SelectColumns(ref list))
			{
				return false;
			}
			ColumnDatum columnData = dlg.GetColumnData();
			Transaction transaction = new Transaction(this.m_doc, "ReplaceColumn");
			foreach (Element element in list)
			{
				if (element != null)
				{
					FamilyInstance familyInstance = element as FamilyInstance;
					if (familyInstance != null)
					{
						XYZ xyz = null;
						if (this.TryGetCenterPoint(familyInstance, out xyz))
						{
							try
							{
								transaction.Start();
								ElementId id = familyInstance.Symbol.Category.Id;
								if ((columnData.IsArch && id.IntegerValue != -2000100) || (!columnData.IsArch && id.IntegerValue == -2000100))
								{
									this.m_doc.DeleteElement(familyInstance);
									this.m_doc.Regenerate();
									this.InsertColumn(columnData, xyz);
								}
								else
								{
									familyInstance.Symbol = columnData.ColSym;
									Line rotLine = YJKLineEx.YJKGetUnBound(xyz, XYZ.BasisZ);
									this.SetColumnParameters(familyInstance, rotLine, columnData);
								}
								transaction.Commit();
							}
							catch
							{
								transaction.RollBack();
							}
						}
					}
				}
			}
			return true;
		}

		private bool TryGetCenterPoint(FamilyInstance familyInstance, out XYZ centerPoint)
		{
			centerPoint = null;
			ColumnProfileAnalyzer columnProfileAnalyzer = new ColumnProfileAnalyzer(this.m_cmdData);
			List<ColumnProfileInfo> list = new List<ColumnProfileInfo>();
			List<Curve> list2 = new List<Curve>();
			columnProfileAnalyzer.GetElementSolids(familyInstance.Symbol);
			foreach (Pole2D pole2D in columnProfileAnalyzer.GetColumnProfile(familyInstance, ref list))
			{
				list2.Add(pole2D.ToCurve(this.m_doc, true));
			}
			List<CurveLoop> list3 = ColumnInsertManage.CreateLoopsByCurves(this.m_doc, list2);
			return list3.Count > 0 && new RevitPolygonDataBean(list3[0], null, 3).TryGetCenterPoint(out centerPoint);
		}

		public static List<CurveLoop> CreateLoopsByCurves(Autodesk.Revit.DB.Document doc, List<Curve> lstCvs)
		{
			List<CurveLoop> lstLoops = new List<CurveLoop>();
			try
			{
				List<Pole2D> lstPole = new List<Pole2D>();
				lstCvs.ForEach(delegate(Curve e)
				{
					Pole2D item = Pole2D.TransformWallToStructure2DPole(e, ElementId.InvalidElementId, 0.0, 0.0);
					lstPole.Add(item);
				});
				new StructureLoopSearcher(doc).GetCellsEdgeLoops(lstPole, false).ForEach(delegate(List<Curve> cvs)
				{
					CurveLoop item = CurveLoop.Create(cvs);
					lstLoops.Add(item);
				});
			}
			catch
			{
			}
			return lstLoops;
		}

		private bool InsertColumnsOperator(ColumnInsertDlg dlg)
		{
			List<XYZ> list = new List<XYZ>();
			bool flag = false;
			switch (dlg.GetCreateColType())
			{
			case CreateColumnType.eSelectPoint:
				dlg.SetInsertPointStateTrue();
				flag = this.GetPointPts(ref list);
				break;
			case CreateColumnType.eSelectAxis:
				flag = this.GetAxisPts(ref list);
				break;
			case CreateColumnType.eSelectGrids:
				flag = this.GetRectPts(ref list);
				break;
			}
			if (!flag)
			{
				return false;
			}
			ColumnDatum columnData = dlg.GetColumnData();
			foreach (XYZ ptInsert in list)
			{
				Transaction transaction = null;
				try
				{
					transaction = new Transaction(this.m_doc, "insertcolumn");
					transaction.Start();
					if (!this.InsertColumn(columnData, ptInsert))
					{
						if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
						{
							transaction.RollBack();
						}
					}
					else
					{
						transaction.Commit();
					}
				}
				catch (Exception)
				{
					if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
					{
						transaction.RollBack();
					}
				}
			}
			return true;
		}

		public bool InsertColumn(ColumnDatum columnData, XYZ ptInsert)
		{
			StructuralType structuralType = 0;
			if (!columnData.IsArch)
			{
                structuralType = (StructuralType)3;
			}
			UnifiedModified.ActivateFamilySymbol(columnData.ColSym);
			FamilyInstance familyInstance = this.m_doc.Create.NewFamilyInstance(ptInsert, columnData.ColSym, columnData.Bottomlevel, structuralType);
			Line rotLine = YJKLineEx.YJKGetUnBound(ptInsert, XYZ.BasisZ);
			this.SetColumnParameters(familyInstance, rotLine, columnData);
			this.m_doc.Regenerate();
			if (!this.CheckColumnInsertOk(familyInstance))
			{
				return false;
			}
			ColumnSplitWallControler columnSplitWallControler = new ColumnSplitWallControler(this.m_uiApplication);
			try
			{
				columnSplitWallControler.ColumnJoinWall(familyInstance, structuralType);
			}
			catch
			{
				return false;
			}
			return true;
		}

		private void SetColumnParameters(FamilyInstance newCol, Line rotLine, ColumnDatum columnData)
		{
			double num = AssistFunc.AngleToRadian(columnData.Angle);
			LocationPoint locationPoint = newCol.Location as LocationPoint;
			if (locationPoint != null)
			{
				num -= locationPoint.Rotation;
			}
			newCol.Location.Rotate(rotLine, num);
			if (!columnData.IsArch)
			{
				this.SetParameter(newCol, BuiltInParameter.STRUCTURAL_MATERIAL_PARAM, columnData.MateralId);
			}
			this.SetParameter(newCol, BuiltInParameter.FAMILY_TOP_LEVEL_PARAM, columnData.Toplevel.Id);
			this.SetParameter(newCol, BuiltInParameter.FAMILY_LEVEL_PARAM, columnData.Bottomlevel.Id);
			this.SetParameter(newCol, BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM, columnData.BottomOffset);
			this.SetParameter(newCol, BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM, columnData.TopOffset);
			this.SetParameter(newCol, BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM, columnData.TopOffset);
		}

		private void SetParameter(FamilyInstance column, BuiltInParameter bPar, ElementId id)
		{
			Parameter parameter = column.get_Parameter(bPar);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set(id);
			}
		}

		private void SetParameter(FamilyInstance column, BuiltInParameter bPar, double value)
		{
			Parameter parameter = column.get_Parameter(bPar);
			if (parameter != null && !parameter.IsReadOnly)
			{
				parameter.Set(value);
			}
		}

		private bool CheckColumnInsertOk(FamilyInstance newCol)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_doc);
			ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(newCol, false);
			filteredElementCollector.WherePasses(elementIntersectsElementFilter);
			filteredElementCollector.Excluding(new List<ElementId>
			{
				newCol.Id
			});
			foreach (Element element in filteredElementCollector)
			{
				if (element.Category.Id.IntegerValue == -2000100 || element.Category.Id.IntegerValue == -2001330 || element.Category.Id.IntegerValue == -2000023 || element.Category.Id.IntegerValue == -2000014)
				{
					TaskDialog taskDialog = new TaskDialog("盈建科提示");
					taskDialog.MainInstruction = "X插入点已有其他不允许相交的设备存在，可能会导致对象重叠，请检查";
					taskDialog.AddCommandLink((TaskDialogCommandLinkId)1001, "继续插入");
					taskDialog.AddCommandLink((TaskDialogCommandLinkId)1002, "取消插入");
                    taskDialog.DefaultButton = (TaskDialogResult)1001;
					taskDialog.TitleAutoPrefix = false;
					this.m_dlg.m_bDoHook = false;
					TaskDialogResult taskDialogResult = taskDialog.Show();
					this.m_dlg.m_bDoHook = true;
                    if ((int)taskDialogResult == 1001)
					{
						return true;
					}
                    if ((int)taskDialogResult == 1002)
					{
						return false;
					}
				}
			}
			return true;
		}

		private bool GetPointPts(ref List<XYZ> arPts)
		{
			try
			{
				XYZ item = new XYZ(0.0, 0.0, 0.0);
				item = this.m_uiDoc.Selection.PickPoint("请点取插入点：");
				arPts.Add(item);
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return false;
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private bool GetAxisPts(ref List<XYZ> arPts)
		{
			try
			{
				AxisFilter axisFilter = new AxisFilter();
				Reference reference = this.m_uiDoc.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, axisFilter, "请选择单根轴线");
				List<Curve> list = new List<Curve>();
				Grid grid = this.m_doc.GetElement(reference) as Grid;
				if (grid != null)
				{
					list.Add(grid.Curve);
				}
				MultiSegmentGrid multiSegmentGrid = this.m_doc.GetElement(reference) as MultiSegmentGrid;
				if (multiSegmentGrid != null)
				{
					list = AxisAssistFunc.GetLocationCurves(this.m_uiApplication, this.m_doc, multiSegmentGrid);
				}
				List<Element> allAxis = AxisAssistFunc.GetAllAxis(this.m_uiApplication);
				IntersectionResultArray intersectionResultArray = null;
				foreach (Curve curve in list)
				{
					foreach (Element element in allAxis)
					{
						Grid grid2 = element as Grid;
						if (grid2 != null)
						{
							Curve curve2 = grid2.Curve;
							curve.Intersect(curve2, out intersectionResultArray);
							if (intersectionResultArray != null && intersectionResultArray.Size == 1)
							{
								XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
								arPts.Add(xyzpoint);
							}
						}
						MultiSegmentGrid multiSegmentGrid2 = element as MultiSegmentGrid;
						if (multiSegmentGrid2 != null)
						{
							new List<Curve>();
							foreach (Curve curve3 in AxisAssistFunc.GetLocationCurves(this.m_uiApplication, this.m_doc, multiSegmentGrid2))
							{
								curve.Intersect(curve3, out intersectionResultArray);
								if (intersectionResultArray != null && intersectionResultArray.Size == 1)
								{
									XYZ xyzpoint2 = intersectionResultArray.get_Item(0).XYZPoint;
									arPts.Add(xyzpoint2);
								}
							}
						}
					}
				}
				AssistFunc.CompressArray(arPts);
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return false;
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private bool GetRectPts(ref List<XYZ> arPts)
		{
			try
			{
				GridFilter gridFilter = new GridFilter();
				IList<Element> list = this.m_uiDoc.Selection.PickElementsByRectangle(gridFilter, "请框选轴线交点");
				IntersectionResultArray intersectionResultArray = null;
				foreach (Element element in list)
				{
					Curve curve = (element as Grid).Curve;
					foreach (Element element2 in list)
					{
						if (!element.Equals(element2))
						{
							Curve curve2 = (element2 as Grid).Curve;
							curve.Intersect(curve2, out intersectionResultArray);
							if (intersectionResultArray != null && intersectionResultArray.Size == 1)
							{
								XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
								arPts.Add(xyzpoint);
							}
						}
					}
				}
				AssistFunc.CompressArray(arPts);
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return false;
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private bool PickColumnOperator(ColumnInsertDlg dlg)
		{
			FamilySymbol fiSymbol = null;
			if (!this.PickOneColumn(ref fiSymbol))
			{
				return false;
			}
			dlg.m_bIsLevelDlg = true;
			dlg.TabNewToTabCur();
			dlg.SelectTreeNode(fiSymbol, false);
			dlg.SetCreateColType(CreateColumnType.eSelectPoint);
			dlg.m_bIsLevelDlg = false;
			return true;
		}

		private bool PickOneColumn(ref FamilySymbol fs)
		{
			try
			{
				ColumnFilter columnFilter = new ColumnFilter();
				Reference reference = this.m_uiDoc.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, columnFilter, "请拾取图面已有柱子");
				FamilyInstance familyInstance = this.m_doc.GetElement(reference) as FamilyInstance;
				fs = familyInstance.Symbol;
			}
			catch
			{
				return false;
			}
			return true;
		}

		private bool SelectColumns(ref List<Element> lstColumn)
		{
			try
			{
				ColumnFilter columnFilter = new ColumnFilter();
				lstColumn = this.m_uiDoc.Selection.PickElementsByRectangle(columnFilter, "请选择需要被替换的柱子").ToList<Element>();
			}
			catch
			{
				return false;
			}
			return true;
		}

		private UIDocument m_uiDoc;

		private Document m_doc;

		private UIApplication m_uiApplication;

		private ExternalCommandData m_cmdData;

		private ColumnInsertDlg m_dlg;
	}
}
